package test.deepin;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * 一个同步工具，用于允许一个或多个线程等待其他线程正在执行的一组操作完成
 * A synchronization aid that allows one or more threads to wait
 * until a set of operations being performed in other threads completes.
 *
 * CountDownLatch初始化时需要传入参数count，await方法代码块会阻塞，直到通过countDown方法的调用去将count降为0，
 * 然后，所有等待的线程将会释放，await等待的操作也会立即执行
 * A {@code CountDownLatch} is initialized with a given <em>count</em>.
 * The await methods block until the current count reaches zero due to invocations of the countDown method
 * , after which all waiting threads are released and any subsequent invocations of await return immediately.
 *
 * This is a one-shot phenomenon -- the count cannot be reset.If you need a version that resets the count, consider using a CyclicBarrier.
 * 由于count不能重置，因此这是个一次性的现象（我的理解，count为0后就会释放，不会再次阻塞，因为count除了countDown方法减小，没有其他方法重置）
 * 如果你希望某个jdk版本能够支持重置count，建议使用CyclicBarrier类代替
 *
 * CountDownLatch是一个通用的同步工具，可以用在很多场景
 * A CountDownLatch is a versatile synchronization tool and can be used for a number of purposes.
 *
 * CountDownLatch初始化时需要一个参数count，这个count用于一个简单的门闩开关：所有的线程都会在'门口'等待，直到一个线程持续调用countDown方法，然后打开门
 * A CountDownLatch initialized with a count of one serves as a simple on/off latch, or gate:
 * all threads invoking {@link #await await} wait at the gate until it is opened by a thread invoking {@link#countDown}.
 *
 * 一个初始化count=N的CountDownLatch对象，可以用于使一个线程等待(N个线程执行完一些操作)或者(某些操作被执行N次)后再执行
 * A {@code CountDownLatch} initialized to <em>N</em> can be used to make one thread wait until <em>N</em> threads have
 * completed some action, or some action has been completed N times.
 *
 *
 * CountDownLatch有一个非常有用的特性，就是线程在count减小到0，继续执行前，不需要线程去调用countDown方法。它在所有线程可以通过之前，
 * 通过让线程等待，很简单的就阻止了线程继续执行，当某个线程将count降为0时，会触发await的线程释放执行
 * A useful property of a {@code CountDownLatch} is that it doesn't require that threads calling {@code countDown} wait for
 * the count to reach zero before proceeding, it simply prevents any thread from proceeding past an {@link #await await} until all
 * threads could pass.
 *
 * 案例使用：场景是一组worker线程，使用两个CountDownLatch对象
 * 第一个是一个开始的标志，用于防止所有worker开始作业，直到driver点头ok
 * 第二个是完成的标志，用于防止driver提前跑路，必须等所有worker忙完
 * Sample usage: Here is a pair of classes in which a group of worker threads use two countdown latches:
 * The first is a start signal that prevents any worker from proceeding until the driver is ready for them to proceed;
 * The second is a completion signal that allows the driver to wait until all workers have completed.

 *<pre> {@code
 class Driver { // ...
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1);
     CountDownLatch doneSignal = new CountDownLatch(N);
     for (int i = 0; i < N; ++i) // create and start threads
        new Thread(new Worker(startSignal, doneSignal)).start();
        doSomethingElse();            // don't let run yet
        startSignal.countDown();      // let all threads proceed
        doSomethingElse();
        doneSignal.await();           // wait for all to finish
     }
 }

 class Worker implements Runnable {
   private final CountDownLatch startSignal;
   private final CountDownLatch doneSignal;
   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
     this.startSignal = startSignal;
     this.doneSignal = doneSignal;
   }
   public void run() {
     try {
       startSignal.await();
       doWork();
       doneSignal.countDown();
     } catch (InterruptedException ex) {} // return;
   }
   void doWork() { ... }
 }}</pre>
 *
 *
 * 另一个典型的用法将问题分为N个部分，每个部分通过一个Runnable去执行功能并countDown，
 * 通过一个Executor去执行这些Runnable，当这些部分都执行完成后，放掉当前await的线程
 * Another typical usage would be to divide a problem into N parts,
 * describe each part with a Runnable that executes that portion and counts down on the latch,
 * and queue all the Runnables to an Executor.
 * When all sub-parts are complete, the coordinating thread will be able to pass through await.
 * (When threads must repeatedly count down in this way, instead use a {@link CyclicBarrier}.)
 *
  <pre> {@code
 class Driver2 { // ...
   void main() throws InterruptedException {
     CountDownLatch doneSignal = new CountDownLatch(N);
     Executor e = ...
 *
     for (int i = 0; i < N; ++i) // create and start threads
       e.execute(new WorkerRunnable(doneSignal, i));
 *
     doneSignal.await();           // wait for all to finish
   }
 }
 *
 class WorkerRunnable implements Runnable {
   private final CountDownLatch doneSignal;
   private final int i;
   WorkerRunnable(CountDownLatch doneSignal, int i) {
     this.doneSignal = doneSignal;
     this.i = i;
   }
   public void run() {
     try {
       doWork(i);
       doneSignal.countDown();
     } catch (InterruptedException ex) {} // return;
   }
 *
   void doWork() { ... }
 }}</pre>
 *
 *
 * 内存一致性的影响：线程会去调用countDown，直到count为0，然后唤醒其他线程的await
 * Memory consistency effects: Until the count reaches zero, actions in a thread prior to calling
 {@code countDown()} happen-before actions following a successful return from a corresponding
 {@code await()} in another thread.
 *
 *

 @since 1.5
 @author Doug Lea
 */
public class CountDownLatch {
    /**
     * CountDownLatch的同步控制
     * 使用AQS（AbstractQueuedSynchronizer）代表count
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;

    /**
     * 构造函数，参数count
     * Constructs a {@code CountDownLatch} initialized with the given count.
     *
     * @param count await线程释放前，countDown必须执行的次数
     * the number of times {@link #countDown} must be invoked before threads can pass through {@link #await}
     *
     * @throws IllegalArgumentException count为负时抛出
     * if {@code count} is negative
     */
    public CountDownLatch(int count) {
        //如果初始化时count < 0，抛出错误
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

    /**
     * 使当前线程等待，直到count减为0，除非当前线程被打断
     * Causes the current thread to wait until the latch has counted down to zero,
     * unless the thread is {@linkplain Thread#interrupt interrupted}.
     *
     * 如果count为0，则当前线程停止阻塞，立即执行
     * 如果count大于0，则当前线程线程会由调度转为不可用，并进入休眠状态，除非两种情况发生：countDown将count减小至0；线程被interrupt
     * If the current count is zero then this method returns immediately.
     * If the current count is greater than zero then the current thread becomes disabled for thread scheduling purposes
     * and lies dormant until one of two things happen:
     * The count reaches zero due to invocations of the {@link #countDown} method;
     * or Some other thread {@linkplain Thread#interrupt interrupts} the current thread.
     *
     * 如果当前线程在方法入口上已经是打断状态，或者在await的时候被打断，将会抛出InterruptedException异常并清除打断状态
     * If the current thread has its interrupted status set on entry to this method;
     * or is {@linkplain Thread#interrupt interrupted} while waiting,
     * then {@link InterruptedException} is thrown and the current thread's interrupted status is cleared.
     * @throws InterruptedException if the current thread is interrupted while waiting
     */
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    /**
     * 使当前线程等待，直到count减为0，除非当前线程被打断，或者走完指定的时间
     * Causes the current thread to wait until the latch has counted down to zero,
     * unless the thread is {@linkplain Thread#interrupt interrupted},
     * or the specified waiting time elapses.
     *
     * 如果count为0，则当前线程停止阻塞，返回true
     * 如果count大于0，则当前线程线程会由调度转为不可用，并进入休眠状态，除非3种情况发生：countDown将count减小至0；线程被interrupt；走完指定的时间
     * <p>If the current count is zero then this method returns immediately with the value {@code true}.
     * <p>If the current count is greater than zero then the current
     * thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happen:
     * The count reaches zero due to invocations of the {@link #countDown} method;
     * or Some other thread {@linkplain Thread#interrupt interrupts} the current thread;
     * or The specified waiting time elapses.
     *
     * 如果当前线程在方法入口上已经是打断状态，或者在await的时候被打断，将会抛出InterruptedException异常并清除打断状态
     * If the current thread has its interrupted status set on entry to this method;
     * or is {@linkplain Thread#interrupt interrupted} while waiting,
     * then {@link InterruptedException} is thrown and the current thread's interrupted status is cleared.
     *
     * 如果指定的时间走完，返回false，不会再等待
     * If the specified waiting time elapses then the value {@code false} is returned.
     * If the time is less than or equal to zero, the method will not wait at all.
     *
     * @param timeout the maximum time to wait 最大的等待时间
     * @param unit the time unit of the {@code timeout} argument 时间单位
     * @return count减到0，返回true，时间走完，返回false
     * {@code true} if the count reached zero and {@code false} if the waiting time elapsed before the count reached zero
     * @throws InterruptedException if the current thread is interrupted while waiting
     */
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    /**
     * 递减count，直到count为0，释放所有等待的线程
     * 如果当前count大于0，count递减
     * 如果初始的count就是0，则释放所有线程
     * 如果当前的current count为0，不会发生啥，区别上面的，因为在递减为0时会去释放线程，而初始就是0则不会
     *
     * Decrements the count of the latch, releasing all waiting threads if the count reaches zero.
     * If the current count is greater than zero then it is decremented.
     * If the new count is zero then all waiting threads are re-enabled for thread scheduling purposes.
     * If the current count equals zero then nothing happens.
     */
    public void countDown() {
        sync.releaseShared(1);
    }

    /**
     * 返回当前的count值，本方法一般用于测试或调试
     * Returns the current count. This method is typically used for debugging and testing purposes.
     * @return the current count
     */
    public long getCount() {
        return sync.getCount();
    }

    /**
     * 返回这个门闩的标志（hash值）和状态（count）
     * 这个状态，放在中括号中，包括'Count ='，紧跟着的是current count
     * Returns a string identifying this latch, as well as its state.
     * The state, in brackets, includes the String {@code "Count ="} followed by the current count.
     * @return a string identifying this latch, as well as its state
     */
    public String toString() {
        return super.toString() + "[Count = " + sync.getCount() + "]";
    }
}
